﻿using System;
using System.Linq;
using DevExpress.ExpressApp;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
using DevExpress.ExpressApp.Updating;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Security.Strategy;
using DevExpress.Xpo;
using DevExpress.ExpressApp.Xpo;
//using DevExpress.Persistent.BaseImpl;
using aztall.Module.BusinessObjects;
using dev = DevExpress.Persistent.BaseImpl;
using DevExpress.ExpressApp.DC;
using System.Collections.Generic;
using System.Reflection;

namespace aztall.Module.DatabaseUpdate
{
	// For more typical usage scenarios, be sure to check out https://documentation.devexpress.com/eXpressAppFramework/clsDevExpressExpressAppUpdatingModuleUpdatertopic.aspx
	public class Updater : ModuleUpdater
	{
		struct metricStruct
		{
			public string MetricType;
			public MetricScope MetricScope;
			public string MetricCode;
			public string MetricDesc;

		};
		IList<Domain> domains = null;
		public Updater(IObjectSpace objectSpace, Version currentDBVersion) :
				base(objectSpace, currentDBVersion)
		{
		}
		public override void UpdateDatabaseAfterUpdateSchema()
		{
			base.UpdateDatabaseAfterUpdateSchema();
			domains = base.ObjectSpace.GetObjects<Domain>();

			#region user and roles
			User sampleUser = ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "User"));
			if (sampleUser == null)
			{
				sampleUser = ObjectSpace.CreateObject<User>();
				sampleUser.UserName = "User";
				sampleUser.SetPassword("");
			}
			Role defaultRole = CreateDefaultRole();
			sampleUser.Roles.Add(defaultRole);

			User domainAdmin = ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "DomainAdmin"));
			if (domainAdmin == null)
			{
				domainAdmin = ObjectSpace.CreateObject<User>();
				domainAdmin.UserName = "domainAdmin";
				domainAdmin.SetPassword("");
			}
			Role DomainAdminRole = CreateDomainAdminRole();
			domainAdmin.Roles.Add(DomainAdminRole);

			User sysAdmin = ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "SysAdmin"));
			if (sysAdmin == null)
			{
				sysAdmin = ObjectSpace.CreateObject<User>();
				sysAdmin.UserName = "SysAdmin";
				// Set a password if the standard authentication type is used
				sysAdmin.SetPassword("");
			}
			// If a role with the Administrators name doesn't exist in the database, create this role
			Role SysAdminRole = ObjectSpace.FindObject<Role>(new BinaryOperator("Name", "Administrators"));
			if (SysAdminRole == null)
			{
				SysAdminRole = ObjectSpace.CreateObject<Role>();
				SysAdminRole.Name = "Administrators";
			}
			SysAdminRole.IsAdministrative = true;
			sysAdmin.Roles.Add(SysAdminRole);
			ObjectSpace.CommitChanges(); //This line persists created object(s). 
			#endregion
			#region Domain
			string[] Domain = new string[] { "DEF", "ASM", "NST" };
			foreach (string d in Domain)
				CreateDomain(d, domains);
			ObjectSpace.CommitChanges();

			domains = base.ObjectSpace.GetObjects<Domain>();

			Domain def = domains.Where(c => c.DomainCode == "DEF").First();
			def.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "SysAdmin")));
			def.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "Administrators")));
			def.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "DomainAdmin")));
			def.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "User")));

			Domain ASM = domains.Where(c => c.DomainCode == "ASM").First();
			ASM.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "SysAdmin")));
			ASM.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "Administrators")));
			ASM.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "DomainAdmin")));
			ASM.Users.Add(ObjectSpace.FindObject<User>(new BinaryOperator("UserName", "User")));

			Env.CurrentDomainOid = ASM.Oid;

			#endregion
			#region config
			IList<Config> configs = base.ObjectSpace.GetObjects<Config>();
			CreateConfig(configs, ConfigGroup.Application, "Password Reset Period", @"Password reset month", ConfigValueType.String, () => "3");
			CreateConfig(configs, ConfigGroup.Application, "Upload File Size", @"Maximum upload file size in MB", ConfigValueType.Integer, () => "5");
			CreateConfig(configs, ConfigGroup.Application, "Culture Code", @"Language Culture Name, https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx", ConfigValueType.String);
			CreateConfig(configs, ConfigGroup.Promotion, "Hide Promotion Store Dates", "1: Hide promotion Store Start Date and Store End Date", ConfigValueType.Boolean, () => "1");
			CreateConfig(configs, ConfigGroup.Promotion, "Hide Promotion Attachments", "1: Hide promotion Attachments tab.", ConfigValueType.Boolean, () => "1");
			CreateConfig(configs, ConfigGroup.Promotion, "Hide Promotion Change History", "1: Hide promotion Change History tab.", ConfigValueType.Boolean, () => "1");
			ObjectSpace.CommitChanges();
			configs = base.ObjectSpace.GetObjects<Config>();
			#endregion
			#region Status
			IList<Status> status = base.ObjectSpace.GetObjects<Status>();

			string[][] StatusList = new string[][]
	{
				new string[] { Status.Sku, "Active", "Can be add/remove from price list."},
				new string[] { Status.Sku, "Inactive", "can be removed from price list but not add to price list." },
				new string[] { Status.Sku, "Terminated", "removed in all price list."},
				new string[] { Status.Promo, "New", "In drafting/proposal. Pending for approved."},
				new string[] { Status.Promo, "Approved", "Can input uplift, PPD, CANN, payment information etc."},
				new string[] { Status.Promo, "Cancelled", "Only New promotion can be cancelled."},
				new string[] { Status.Promo, "Finished", "After all uplift, PPD, CANN, payment etc are input. Pending for performance review."},
				new string[] { Status.Promo, "Closed", "After performance reviewed." },
				new string[] { Status.Promo, "Archived", "Archived" },
				new string[] { Status.ActiveInactive, "Active", "Available for selection" },
				new string[] { Status.ActiveInactive, "Inactive", "Not available for selection" }
	};
			foreach (string[] item in StatusList)
			{
				CreateStatus(status, item[0], item[1], item[2]);
			}
			ObjectSpace.CommitChanges();
			status = base.ObjectSpace.GetObjects<Status>();
			#endregion
			#region Sku
			
			string[][] Skus = new string[][]
			{
				new string[] {"DEF", "S001", "Sku S001", "Case", "Bag", "12", "Active", "10"},
				new string[] {"DEF", "S002", "Sku S002", "Case", "Box", "05", "Active","20"},
				new string[] {"DEF", "S003", "Sku S003", "Kg", "Kg", "1", "Active","30"},
				new string[] {"DEF", "S004", "Sku S004", "Case", "Box", "5", "Inactive", "40" },
				new string[] {"DEF", "S005", "Sku S005", "Case", "Box", "5", "Terminated", "50" },
				new string[] {"ASM", "ASM999", "ASM Sku999", "Case", "Box", "5", "Active", "12.5" },
				new string[] {"ASM", "S001", "ASM Sku001", "Case", "Box", "5", "Active", "12.5" },
				new string[] {"ASM", "S002", "ASM Sku002", "Case", "Box", "5", "Active", "12.5" },
			};
			foreach (string[] item in Skus)
			{
				Sku newItem = CreateSku(item[0], item[1], item[2], item[3], item[4], item[5], item[6], item[7]);
			}
			ObjectSpace.CommitChanges();
			#endregion
			#region Customer
			string[][] Customers = new string[][]
			{
				new string[] {"DEF", "C001", "Adeco Super Market", "Active"},
				new string[] {"DEF", "C002", "7-11 NYC", "Active"},
				new string[] {"DEF", "C003", "Timothy", "Inactive"},
				new string[] {"ASM", "ASM", "Vankee NorthWest", "Active"},
				new string[] {"ASM", "C001", "ASM:Adeco Super Market", "Active"},
				new string[] {"ASM", "C002", "ASM:7-11 NYC", "Active"},
			};
			foreach (string[] item in Customers)
			{
				CreateCustomer(domains, item[0], item[1], item[2], item[3]);
			}
			ObjectSpace.CommitChanges();
			#endregion
			#region Metric
			IList<Metric> Metrics = base.ObjectSpace.GetObjects<Metric>();

			metricStruct[] metrics = new metricStruct[]
			{
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.Promotion, MetricCode = "1010", MetricDesc = "Fix amount Per Promotion, Value = Rate$" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.Promotion, MetricCode = "1011", MetricDesc = "Fix amount Per Each Customer, Rate$ * Number of Customers" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.Customer, MetricCode = "1012", MetricDesc = "Fix amount Per the Customer, Rate$" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.Promotion, MetricCode = "1013", MetricDesc = "Fix amount Per Each Sku, Rate$ * Number of Promotion Skus" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.Sku, MetricCode = "1014", MetricDesc = "Fix amount Per the Sku, Rate$" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.Promotion, MetricCode = "1015", MetricDesc = "Fix amount Per Promotion Day, Rate$ * Promotion Days" },

				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2011", MetricDesc = "Per Promotion Volume, Rate$ * (Uplift)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2012", MetricDesc = "Per Promotion Volume, Rate$ * (CANN)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2013", MetricDesc = "Per Promotion Volume, Rate$ * (PPD)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2014", MetricDesc = "Per Actual Volume, Rate$ * Actual Volume during Promotion" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2015", MetricDesc = "Per Base Volume, Rate$ * Base Volume during Promotion" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2050", MetricDesc = "Per Promotion Volume, Rate$ * (Uplift + PPD + Cann)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "2051", MetricDesc = "Per Projection Volume, Rate$ * (Base Volume during Promotion + Uplift + PPD + Cann)" },

				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3011", MetricDesc = "Percentage Per Actual Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Promotion Uplift)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3012", MetricDesc = "Percentage Per Actual Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Promotion CANN)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3013", MetricDesc = "Percentage Per Actual Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Promotion PPD)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3014", MetricDesc = "Percentage Per Actual Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Actual Volume during Promotion)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3015", MetricDesc = "Percentage Per Base Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Base Volume during Promtion)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3050", MetricDesc = "Percentage Per Promotion Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Uplift + PPD + Cann)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "3051", MetricDesc = "Percentage Per Projection Volume, (Rate% / 100) * (Unit Price at Promo Start Date) * (Base Volume during Promotion + Uplift + PPD + Cann)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "4011", MetricDesc = "Per Retail Base Volume (in retail UOM), Rate$ * Retail Base Volume during Promotion" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "4012", MetricDesc = "Per Retail Actual Volume (in retail UOM), Rate$ * Retail Actual Volume during Promotion" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "4050", MetricDesc = "Per Retail Promo Volume (in retail UOM), Rate$ * (Retail Actual Volume - Retail Base Volume)" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "5010", MetricDesc = "Percent Per Retail Base Volume (in retail UOM), (Rate% / 100) * (Retail Unit Price ) * Retail Base Volume during Promotion" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "5011", MetricDesc = "Percent Per Retail Actual Volume (in retail UOM), (Rate% / 100) * Retail Unit Price * Retail Actual Volume during Promotion" },
				new metricStruct() { MetricType = MetricType.PromoCost, MetricScope = MetricScope.CustomerSku, MetricCode = "5050", MetricDesc = "Percent Per Retail Promo Volume (in retail UOM), (Rate% / 100) * Retail Unit Price  * (Retail Actual Volume - Retail Base Volume) during Promotion" },

				new metricStruct() { MetricType = MetricType.PromoVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9010", MetricDesc = "Uplift Volume" },
				new metricStruct() { MetricType = MetricType.PromoVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9011", MetricDesc = "Cannibalized Volume (Cann)" },
				new metricStruct() { MetricType = MetricType.PromoVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9012", MetricDesc = "Post Promotion Dip Volume (PPD)" },

				new metricStruct() { MetricType = MetricType.SalesVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9013", MetricDesc = "Base Volume" },
				new metricStruct() { MetricType = MetricType.SalesVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9014", MetricDesc = "Actual Volume" },

				new metricStruct() { MetricType = MetricType.PromoVolume, MetricScope = MetricScope.Derived, MetricCode = "9050", MetricDesc = "Promotion Volume, Uplift + PPD + Cann" },
				new metricStruct() { MetricType = MetricType.PromoVolume, MetricScope = MetricScope.Derived, MetricCode = "9051", MetricDesc = "Projection Volume: Total BaseVol during Promotion  + Uplift + PPD + Cann" },

				new metricStruct() { MetricType = MetricType.SalesVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9120", MetricDesc = "Retail Base Volume" },
				new metricStruct() { MetricType = MetricType.SalesVolume, MetricScope = MetricScope.CustomerSku, MetricCode = "9121", MetricDesc = "Retail Actual Volume" },
				new metricStruct() { MetricType = MetricType.SalesVolume, MetricScope = MetricScope.Derived, MetricCode = "9151", MetricDesc = "Retail Promotion Volume: Retail Actual Volume - Retail Actual Base Volumn during Promotion" }
			};
			foreach (metricStruct m in metrics)
				CreateMetric(Metrics, m);
			Metrics = base.ObjectSpace.GetObjects<Metric>();


			//Assembly asm = typeof(Metric).Assembly;
			//var metricTypes = asm.GetTypes().Where(t => t.BaseType == typeof(MetricPromoCost) || t.BaseType == typeof(MetricPromoVolume));
			//foreach (Type t in metricTypes)
			//{
			//	CreateMetric(t);
			//}
			//ObjectSpace.CommitChanges();
			#endregion
			CreatePriceList();
			ObjectSpace.CommitChanges();
			CreateDW();
			ObjectSpace.CommitChanges();
			CreatePromo();
			ObjectSpace.CommitChanges();



		}
		public override void UpdateDatabaseBeforeUpdateSchema()
		{
			base.UpdateDatabaseBeforeUpdateSchema();
			//if(CurrentDBVersion < new Version("1.1.0.0") && CurrentDBVersion > new Version("0.0.0.0")) {
			//    RenameColumn("DomainObject1Table", "OldColumnName", "NewColumnName");
			//}
		}
		private Role CreateDefaultRole()
		{
			Role defaultRole = ObjectSpace.FindObject<Role>(new BinaryOperator("Name", "Default"));
			if (defaultRole == null)
			{
				defaultRole = ObjectSpace.CreateObject<Role>();
				defaultRole.Name = "Default";
			}

			defaultRole.AddObjectAccessPermission<User>("[Oid] = CurrentUserId()", SecurityOperations.ReadOnlyAccess);
			defaultRole.AddMemberAccessPermission<User>("ChangePasswordOnFirstLogon", SecurityOperations.Write, "[Oid] = CurrentUserId()");
			defaultRole.AddMemberAccessPermission<User>("StoredPassword", SecurityOperations.Write, "[Oid] = CurrentUserId()");
			defaultRole.SetTypePermissionsRecursively<Role>(SecurityOperations.Read, SecuritySystemModifier.Allow);

			defaultRole.SetTypePermissionsRecursively<dev.ModelDifference>(SecurityOperations.ReadWriteAccess, SecuritySystemModifier.Allow);
			defaultRole.SetTypePermissionsRecursively<dev.ModelDifferenceAspect>(SecurityOperations.ReadWriteAccess, SecuritySystemModifier.Allow);

			defaultRole.SetTypePermissionsRecursively<RootObject>(SecurityOperations.FullAccess, SecuritySystemModifier.Allow);

			defaultRole.SetTypePermissionsRecursively<Config>(SecurityOperations.CRUDAccess, SecuritySystemModifier.Deny);
			defaultRole.SetTypePermissionsRecursively<Config>(SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);
			defaultRole.SetTypePermissionsRecursively<ConfigValue>(SecurityOperations.CRUDAccess, SecuritySystemModifier.Deny);
			defaultRole.SetTypePermissionsRecursively<ConfigValue>(SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);

			return defaultRole;
		}
		private Role CreateDomainAdminRole()
		{
			Role domainAdminRole = ObjectSpace.FindObject<Role>(new BinaryOperator("Name", "DomainAdmin"));
			if (domainAdminRole == null)
			{
				domainAdminRole = ObjectSpace.CreateObject<Role>();
				domainAdminRole.Name = "DomainAdmin";
			}

			domainAdminRole.AddObjectAccessPermission<User>("[Oid] = CurrentUserId()", SecurityOperations.ReadOnlyAccess);
			domainAdminRole.AddMemberAccessPermission<User>("ChangePasswordOnFirstLogon", SecurityOperations.Write, "[Oid] = CurrentUserId()");
			domainAdminRole.AddMemberAccessPermission<User>("StoredPassword", SecurityOperations.Write, "[Oid] = CurrentUserId()");

			domainAdminRole.SetTypePermissionsRecursively<RootObject>(SecurityOperations.FullAccess, SecuritySystemModifier.Allow);

			domainAdminRole.SetTypePermissionsRecursively<Config>(SecurityOperations.CRUDAccess, SecuritySystemModifier.Deny);
			domainAdminRole.SetTypePermissionsRecursively<Config>(SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);
			domainAdminRole.AddMemberAccessPermission<Config>("Values", SecurityOperations.ReadWriteAccess);

			domainAdminRole.SetTypePermissionsRecursively<dev.ModelDifference>(SecurityOperations.ReadWriteAccess, SecuritySystemModifier.Allow);
			domainAdminRole.SetTypePermissionsRecursively<dev.ModelDifferenceAspect>(SecurityOperations.ReadWriteAccess, SecuritySystemModifier.Allow);

			return domainAdminRole;
		}
		private Domain CreateDomain(string domainCode, IList<Domain> domains)
		{
			var newItem = domains.Where(c => c.DomainCode == domainCode).FirstOrDefault();
			if (newItem == null)
			{
				newItem = ObjectSpace.CreateObject<Domain>();
				newItem.DomainCode = domainCode;
			}
			return newItem;
		}
		private Config CreateConfig(IList<Config> configs, ConfigGroup configGroup, string configName, string description = "", ConfigValueType valueType = ConfigValueType.String, Func<string> defaultValue = null)
		{

			var newItem = configs.Where(c => c.ConfigGroup == configGroup && c.ConfigName == configName).FirstOrDefault();
			if (newItem == null)
			{
				newItem = ObjectSpace.CreateObject<Config>();
				newItem.ConfigGroup = configGroup;
				newItem.ConfigName = configName;
				newItem.ValueType = valueType;
				newItem.Description = description;

				if (defaultValue != null)
				{
					var configValue = this.ObjectSpace.CreateObject<ConfigValue>();
					configValue.Value = defaultValue();
					newItem.Values.Add(configValue);
				}
			}
			return newItem;
		}
		private Sku CreateSku(string domainCode, string skuCode, string skuDesc, string customerUOM, string retailUOM, string uomRatio, string statusCode, string UnitPrice)
		{
			int DomainOid = domains.Where(c => c.DomainCode == domainCode).First().Oid;
			var newItem = ObjectSpace.FindObject<Sku>(
							GroupOperator.Combine(GroupOperatorType.And,
																new BinaryOperator("Domain.Oid", DomainOid),
																new BinaryOperator("SkuCode", skuCode)
															)
					);
			if (newItem == null)
			{
				newItem = ObjectSpace.CreateObject<Sku>();
				newItem.Domain = ObjectSpace.FindObject<Domain>(new BinaryOperator("DomainCode", domainCode));
				newItem.SkuCode = skuCode;
				newItem.SkuName = skuDesc;
				newItem.CustomerUOM = customerUOM;
				newItem.RetailUOM = retailUOM;
				newItem.UOMRatio = double.Parse(uomRatio);
				newItem.Status = ObjectSpace.FindObject<Status>(new BinaryOperator("StatusCode", statusCode));
				newItem.StdPrice = double.Parse(UnitPrice);
				newItem.RetailPrice = double.Parse(UnitPrice) * double.Parse(UnitPrice);
			}
			return newItem;
		}
		private Customer CreateCustomer(IList<Domain> domains, string domainCode, string customerCode, string customerName, string statusCode)
		{
			int DomainOid = domains.Where(c => c.DomainCode == domainCode).First().Oid;

			var newitem = ObjectSpace.FindObject<Customer>(
							GroupOperator.Combine(GroupOperatorType.And,
																new BinaryOperator("Domain.Oid", DomainOid),
																new BinaryOperator("CustomerCode", customerCode)
															)
					);
			if (newitem == null)
			{
				newitem = ObjectSpace.CreateObject<Customer>();
				newitem.Domain = ObjectSpace.FindObject<Domain>(new BinaryOperator("DomainCode", domainCode));
				newitem.CustomerCode = customerCode;
				newitem.CustomerName = customerName;
				newitem.Status = ObjectSpace.FindObject<Status>(CriteriaOperator.Parse("Category = 'ActiveInactive' and StatusCode = '" + statusCode + "'"));
			}
			return newitem;
		}
		private Metric CreateMetric(IList<Metric> Metrics, metricStruct m)
		{
			var newItem = Metrics.Where(c => c.MetricCode == m.MetricCode).FirstOrDefault();
			if (newItem == null)
			{
				newItem = ObjectSpace.CreateObject<Metric>();
				newItem.MetricCode = m.MetricCode;
				newItem.MetricDesc = m.MetricDesc;
				newItem.MetricScope = m.MetricScope;
				newItem.MetricType = m.MetricType;
			}
			return newItem;
		}
		private void CreatePriceList()
		{
			#region PL2016
			var PL2016 = ObjectSpace.FindObject<PriceList>(new BinaryOperator("PriceListID", "PL_2016"));
			if (PL2016 == null)
			{
				PL2016 = ObjectSpace.CreateObject<PriceList>();
				PL2016.PriceListID = "PL_2016";
				PL2016.PriceListName = "Standard price for all customers on all skus, year 2016";
				PL2016.AllCustomers = true;
				PL2016.AllSkus = true;
				PL2016.StartDate = new DateTime(2016, 01, 01);
				PL2016.EndDate = new DateTime(2016, 12, 31);
			}
			#endregion
			#region PL2016S001
			var PL2016S001 = ObjectSpace.FindObject<PriceList>(new BinaryOperator("PriceListID", "PL_2016_S001"));
			if (PL2016S001 == null)
			{
				PL2016S001 = ObjectSpace.CreateObject<PriceList>();
				PL2016S001.PriceListID = "PL_2016_S001";
				PL2016S001.PriceListName = "All customers on item S001 in year 2016";
				PL2016S001.AllCustomers = true;
				PL2016S001.AllSkus = false;
				PL2016S001.StartDate = new DateTime(2016, 01, 01);
				PL2016S001.EndDate = new DateTime(2016, 12, 31);

				var plsku1 = ObjectSpace.CreateObject<PriceListSku>();
				plsku1.Sku = ObjectSpace.FindObject<Sku>(new BinaryOperator("SkuCode", "S001"));
				plsku1.UnitPrice = 12.0;
				PL2016S001.PriceListSkus.Add(plsku1);
			}
			#endregion
			#region PLD003
			var PL2016C001S001 = ObjectSpace.FindObject<PriceList>(new BinaryOperator("PriceListID", "PL_2016_C001_S001"));
			if (PL2016C001S001 == null)
			{
				PL2016C001S001 = ObjectSpace.CreateObject<PriceList>();
				PL2016C001S001.PriceListID = "PL_2016_C001_S001";
				PL2016C001S001.PriceListName = "Customer C001 on item S001 in year 2016";
				PL2016C001S001.AllCustomers = false;
				PL2016C001S001.AllSkus = false;
				PL2016C001S001.StartDate = new DateTime(2016, 01, 01);
				PL2016C001S001.EndDate = new DateTime(2016, 12, 31);

				var plsku1 = ObjectSpace.CreateObject<PriceListSku>();
				plsku1.Sku = ObjectSpace.FindObject<Sku>(new BinaryOperator("SkuCode", "S001"));
				plsku1.UnitPrice = 10;
				PL2016C001S001.PriceListSkus.Add(plsku1);
				Customer C001 = ObjectSpace.FindObject<Customer>(new BinaryOperator("CustomerCode", "C001"));
				PL2016C001S001.Customers.Add(C001);
			}
			#endregion

		}
		private void CreateDW()
		{
			#region base volume 120 for customer C001 and Sku S001
			DW dw1 = ObjectSpace.CreateObject<DW>(); ;
			dw1.FromDate = new DateTime(2016, 01, 01);
			dw1.ToDate = new DateTime(2016, 12, 31);

			Customer cust1 = ObjectSpace.FindObject<Customer>(CriteriaOperator.Parse("Domain.Oid = ? and CustomerCode = 'C001'", Env.CurrentDomainOid));
			dw1.Customer = cust1;

			Sku sku1 = ObjectSpace.FindObject<Sku>(CriteriaOperator.Parse("Domain.Oid = ? and SkuCode = 'S001'", Env.CurrentDomainOid));
			dw1.Sku = sku1;

			dw1.Metric = ObjectSpace.FindObject<Metric>(CriteriaOperator.Parse("MetricCode = ?", VolumeMetricCode.Base));
			dw1.Value = 120;

			dw1.Save();

			#endregion
			#region Actual volumn 150 for customer C001 and Sku S001
			DW dw2 = ObjectSpace.CreateObject<DW>(); ;
			dw2.FromDate = new DateTime(2016, 01, 01);
			dw2.ToDate = new DateTime(2016, 01, 31);

			dw2.Customer = cust1;

			dw2.Sku = sku1;

			dw2.Metric = ObjectSpace.FindObject<Metric>(CriteriaOperator.Parse("MetricCode = ?", VolumeMetricCode.Actual));
			dw2.Value = 150;

			dw2.Save();
			#endregion
		}
		private Status CreateStatus(IList<Status> status, string category, string statusCode, string statusDesc)
		{
			var newItem = status.Where(c => c.Category == category && c.StatusCode == statusCode).FirstOrDefault();
			if (newItem == null)
			{
				newItem = ObjectSpace.CreateObject<Status>();
				newItem.Category = category;
				newItem.StatusCode = statusCode;
				newItem.StatusDesc = statusDesc;
			}
			return newItem;
		}
		private void CreatePromo()
		{
			var domain = base.ObjectSpace.FindObject<Domain>(CriteriaOperator.Parse("DomainCode = 'ASM'"));
			var p0 = base.ObjectSpace.FindObject<Promo>(CriteriaOperator.Parse("Domain.Oid = ? and PromoCode = 'ASM.P201601'", domain.Oid));
			if (p0 == null)
			{
				p0 = ObjectSpace.CreateObject<Promo>();
				p0.Domain = domain;
				p0.PromoCode = "ASM.P201601";

				p0.PromoName = domain.DomainCode + ": " + "Sample Promotion";
				p0.StartDate = new DateTime(2016, 01, 01);
				p0.EndDate = new DateTime(2016, 01, 31);
				p0.StoreStartDate = p0.StartDate;
				p0.StoreEndDate = p0.EndDate;

			}
			var newItem = base.ObjectSpace.FindObject<Promo>(CriteriaOperator.Parse("Domain.Oid = ? and PromoCode = 'P201601'", Env.CurrentDomainOid));
			if (newItem == null)
			{
				newItem = ObjectSpace.CreateObject<Promo>();
				newItem.Domain = base.ObjectSpace.FindObject<Domain>(CriteriaOperator.Parse("Oid = ?", Env.CurrentDomainOid));
				newItem.PromoCode = "P201601";
				newItem.PromoName = "Sample Promotion";
				newItem.StartDate = new DateTime(2016, 01, 01);
				newItem.EndDate = new DateTime(2016, 01, 31);
				newItem.StoreStartDate = newItem.StartDate;
				newItem.StoreEndDate = newItem.EndDate;


				Customer cust1 = ObjectSpace.FindObject<Customer>(CriteriaOperator.Parse("Domain.Oid = ? and CustomerCode = 'C001'", Env.CurrentDomainOid));
				Customer cust2 = ObjectSpace.FindObject<Customer>(CriteriaOperator.Parse("Domain.Oid = ? and CustomerCode = 'C002'", Env.CurrentDomainOid));
				newItem.Customers.AddRange(new Customer[] { cust1, cust2 });

				Sku sku1 = ObjectSpace.FindObject<Sku>(CriteriaOperator.Parse("Domain.Oid = ? and SkuCode = 'S001'", Env.CurrentDomainOid));
				Sku sku2 = ObjectSpace.FindObject<Sku>(CriteriaOperator.Parse("Domain.Oid = ? and SkuCode = 'S002'", Env.CurrentDomainOid));
				newItem.Skus.AddRange(new Sku[] { sku1, sku2 });



				PromoCost cost1 = ObjectSpace.CreateObject<PromoCost>();
				cost1.Metric = ObjectSpace.FindObject<Metric>(CriteriaOperator.Parse("MetricCode = ?", CostMetricCode.PerEachCustomer));
				cost1.Rate = 100;
				PromoCost cost2 = ObjectSpace.CreateObject<PromoCost>();
				cost2.Metric = ObjectSpace.FindObject<Metric>(CriteriaOperator.Parse("MetricCode = ?", CostMetricCode.PerPromotion));
				cost2.Rate = 500;

				PromoCost cost3 = ObjectSpace.CreateObject<PromoCost>();
				cost3.Metric = ObjectSpace.FindObject<Metric>(CriteriaOperator.Parse("MetricCode = ?", CostMetricCode.PerPromoVol));
				cost3.Customer = cust1;
				cost3.Sku = sku1;
				cost3.Rate = 2;

				PromoCost cost4 = ObjectSpace.CreateObject<PromoCost>();
				cost4.Metric = ObjectSpace.FindObject<Metric>(CriteriaOperator.Parse("MetricCode = ?", CostMetricCode.PerBaseVol));
				cost4.Customer = cust1;
				cost4.Sku = sku1;
				cost4.Rate = 1;

				newItem.PromoCosts.AddRange(new PromoCost[] { cost1, cost2, cost3, cost4 });

				PromoVol vol1 = ObjectSpace.CreateObject<PromoVol>();
				vol1.Customer = cust1;
				vol1.Sku = sku1;
				vol1.FromDate = newItem.StartDate;
				vol1.ToDate = newItem.EndDate;
				vol1.Uplift = 100;

				PromoVol vol2 = ObjectSpace.CreateObject<PromoVol>();
				vol2.Customer = cust1;
				vol2.Sku = sku1;
				vol2.FromDate = newItem.EndDate.AddDays(1);
				vol2.ToDate = newItem.EndDate.AddDays(5);
				vol2.PPD = -5;

				newItem.PromoVols.AddRange(new PromoVol[] { vol1, vol2 });

				//newItem.UpdatePromoCosts(false);

				newItem.Save();

			}

		}
	}
}
